package com.woody.aggregate.application.service.contract.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.woody.aggregate.application.service.contract.ContractService;
import com.woody.aggregate.contract.dto.BatchSaveContractDTO;
import com.woody.aggregate.contract.dto.ContractHaveNewVersionDTO;
import com.woody.aggregate.contract.dto.ManageListDTO;
import com.woody.aggregate.contract.dto.QueryContractDTO;
import com.woody.aggregate.contract.enums.AggreContractState;
import com.woody.aggregate.contract.vo.ContractVO;
import com.woody.aggregate.domain.contract.ContractRecord;
import com.woody.aggregate.domain.contract.ContractTemplate;
import com.woody.aggregate.infrastructure.contract.entity.ContractRecordEntity;
import com.woody.aggregate.repository.ContractRecordRepository;
import com.woody.base.exception.BaseException;
import com.woody.base.util.ResponseUtil;
import com.woody.common.api.dto.ContractSyncDTO;
import com.woody.common.api.enums.ContractType;
import com.woody.common.api.vo.CommonContractVO;
import com.woody.common.feign.ESignFeignClient;
import com.woody.common.web.util.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author hzy
 * @date 2025/2/24 下午1:46
 */
@Service
@Slf4j
public class ContractServiceImpl implements ContractService {


    @Resource
    private ESignFeignClient eSignFeignClient;

    @Resource
    private ContractRecordRepository contractRecordRepository;


    /**
     * 店铺合同列表
     * @param
     * @return
     */
    @Override
    public Map<String,List<ContractVO>> shopContractList(Long customerId,Integer customerType) {
        Map<String, List<ContractVO>> map = new HashMap<>();

        // 查询最新模版1
        List<String> contractTypeList = Collections.singletonList(ContractType.SHOP_SIGN.name());
        Map<String, ContractTemplate> templateMap = ContractTemplate.getNewVersionTemplate(contractTypeList);

        if (Objects.isNull(templateMap)){
            return map;
        }
        // 查询合同记录
        List<ContractRecord> records = ContractRecord.findListByCustomerId(customerId,customerType);
        // 合同记录按照type分组
        Map<String, List<ContractRecord>> recordMap = records.stream().collect(Collectors.groupingBy(ContractRecord::getType));

        // 查询待签署的合同k
        Map<String, CommonContractVO> unSignMap = new HashMap<>();
        List<CommonContractVO> unSignList = ResponseUtil.getSucRes(eSignFeignClient.getUnSignContract(customerId));
        if (CollUtil.isNotEmpty(unSignList)){
            unSignMap = unSignList.stream().collect(Collectors.toMap(CommonContractVO::getContractType, Function.identity()));

        }

        for (Map.Entry<String, ContractTemplate> entry : templateMap.entrySet()) {
            List<ContractVO> list = new ArrayList<>();
            String type = entry.getKey();
            ContractTemplate template = entry.getValue();

            // 合同记录
            List<ContractRecord> recordList = recordMap.get(type);

            // 构建未签署的合同
            ContractVO unSignContract = this.buildContractByUnSign(unSignMap, template);
            if (unSignContract!=null){
                list.add(unSignContract);
            }

            //如果没合同记录 和 未签署的合同  根据模版构建一个待换签
            if (unSignContract == null && CollUtil.isEmpty(recordList)){
                ContractVO contractVO = this.buildContractByTemplate(template);
                map.put(type, Collections.singletonList(contractVO));
                continue;
            }

            // 当前有新版本且没有未签署的合同 构建一个待换签的合同
            if (unSignContract == null){
                ContractVO contractByVersion = this.buildContractByVersion(recordList, template);
                if (contractByVersion!=null){
                    list.add(contractByVersion);
                }
            }

            // 添加合同历史记录
            List<ContractVO> contractByRecordList = this.buildContractByRecordList(recordList);
            if (CollUtil.isNotEmpty(contractByRecordList)){
                list.addAll(contractByRecordList);
            }


            // 根据版本排序
            if (CollUtil.isNotEmpty(list)){
                list = list.stream().sorted(Comparator.comparing(ContractVO::getVersion).reversed()).collect(Collectors.toList());
                map.put(type,list);
            }
        }
        return map;
    }

    /**
     * 是否含有新版本
     * @param dto
     * @return
     */
    @Override
    public Boolean haveNewVersion(ContractHaveNewVersionDTO dto) {
        log.info("haveNewVersion req:{}", JSONUtil.toJsonStr(dto));
        Map<String, ContractTemplate> templateMap = ContractTemplate.getNewVersionTemplate(Collections.singletonList(dto.getType()));
        if (templateMap == null){
            log.info("haveNewVersion templateMap is null");
            return false;
        }
        ContractTemplate template = templateMap.get(dto.getType());
        List<ContractRecord> list = ContractRecord.findListByCustomerIdAndType(dto.getCustomerId(), dto.getType(),dto.getCustomerType());
        if (CollUtil.isEmpty(list)){
            log.info("haveNewVersion list is null");
            return true;
        }
        ContractRecord contractRecord = list.stream().max(Comparator.comparingDouble(ContractRecord::getVersion)).get();
        if (template.getVersion()>contractRecord.getVersion()){
            return true;
        }
        return false;
    }

    /**
     * 我的合同管理
     * @param dto
     * @return
     */
    @Override
    public List<ContractVO> manageList(ManageListDTO dto) {
        // 已完成
        List<ContractRecord> records = ContractRecord.findListByCustomerId(dto.getCustomerId(),dto.getCustomerType());
        if (dto.getContractState().equals(AggreContractState.SIGNED.getType())){
            List<ContractVO> contractVOS = this.buildContractByRecordList(records);
            return contractVOS;
        }else {
            List<ContractVO> list = new ArrayList<>();
            // 合同记录按照type分组
            Map<String, List<ContractRecord>> recordMap = records.stream().collect(Collectors.groupingBy(ContractRecord::getType));

            // 查询最新模版
            List<String> contractTypeList = Collections.singletonList(ContractType.SHOP_SIGN.name());
            Map<String, ContractTemplate> templateMap = ContractTemplate.getNewVersionTemplate(contractTypeList);

            // 查询待签署的合同
            Map<String, CommonContractVO> unSignMap = new HashMap<>();
            List<CommonContractVO> unSignList = ResponseUtil.getSucRes(eSignFeignClient.getUnSignContract(dto.getCustomerId()));
            if (CollUtil.isNotEmpty(unSignList)){
                unSignMap = unSignList.stream().collect(Collectors.toMap(CommonContractVO::getContractType, Function.identity()));

            }

            for (Map.Entry<String, ContractTemplate> entry : templateMap.entrySet()) {
                ContractTemplate template = entry.getValue();
                String type = entry.getKey();
                List<ContractRecord> recordList = recordMap.get(type);

                // 构建未签署的合同
                ContractVO unSignContract = this.buildContractByUnSign(unSignMap, template);
                if (unSignContract!=null){
                    list.add(unSignContract);
                }

                //如果没合同记录 和 未签署的合同  根据模版构建一个待换签
                if (unSignContract == null && CollUtil.isEmpty(recordList)){
                    ContractVO contractVO = this.buildContractByTemplate(template);
                    list.add(contractVO);
                    continue;
                }

                // 当前有新版本且没有未签署的合同 构建一个待换签的合同
                if (unSignContract == null){
                    ContractVO contractByVersion = this.buildContractByVersion(recordList, template);
                    if (contractByVersion!=null){
                        list.add(contractByVersion);
                    }

                }
            }
            return list;
        }
    }

    @Override
    @Transactional
    public void contractSync(ContractSyncDTO dto) {
        String type = dto.getType();
        Map<String, ContractTemplate> templateMap = ContractTemplate.getNewVersionTemplate(Collections.singletonList(type));
        if (templateMap == null){
            log.info("contractSync 模版不存在{}",type);
            throw new BaseException("模版不存在");
        }
        ContractTemplate template = templateMap.get(type);
        if (template == null){
            log.info("contractSync 模版不存在{}",type);
            throw new BaseException("模版不存在");
        }
        ContractRecord contractRecord = new ContractRecord();
        contractRecord.setTemplateId(template.getTemplateId());
        contractRecord.setCustomerId(dto.getCustomerId());
        contractRecord.setBizId(dto.getBizId());
        contractRecord.setType(template.getType());
        contractRecord.setContractName(template.getContractName());
        contractRecord.setVersion(template.getVersion());
        contractRecord.setContractLink(dto.getContractLink());
        contractRecord.setContractUrl(dto.getContractUrl());
        contractRecord.setContractStartTime(dto.getContractStartTime());
        contractRecord.setContractEndTime(dto.getContractEndTime());
        contractRecord.setContractState(AggreContractState.SIGNED.getType());
        contractRecord.create();
    }

    @Override
    @Transactional
    public void batchSaveContract(BatchSaveContractDTO dto) {
        if (dto.getList().size()>1000){
            throw new BaseException("批量插入数量过多");
        }
        List<BatchSaveContractDTO.SaveContractDTO> list = dto.getList();
        List<ContractRecord> contractRecords = JacksonUtil.reGroupArray(list, ContractRecord[].class);
        contractRecordRepository.batchSaveModel(contractRecords);
    }

    @Override
    public ContractVO queryContract(QueryContractDTO dto) {
        ContractRecord contractRecord = ContractRecord.findByUk(dto.getCustomerId(), dto.getCustomerType(), dto.getType(), dto.getVersion());
        if (contractRecord == null){
            return null;
        }
        ContractVO contractVO = new ContractVO();
        contractVO.setContractName(contractRecord.getContractName());
        contractVO.setContractState(AggreContractState.SIGNED.getType());
        Date date = new Date();
        if (contractRecord.getContractEndTime()!=null && contractRecord.getContractEndTime().getTime()>date.getTime()){
            contractVO.setContractState(AggreContractState.EXPIRE.getType());
        }
        contractVO.setVersion("V"+contractRecord.getVersion());
        contractVO.setCustomerId(contractRecord.getCustomerId());
        contractVO.setContractStartTime(contractRecord.getContractStartTime());
        contractVO.setContractEndTime(contractRecord.getContractEndTime());
        contractVO.setContractUrl(contractRecord.getContractUrl());
        contractVO.setContractLink(contractRecord.getContractLink());
        contractVO.setCreateTime(contractRecord.getCreateTime());
        return contractVO;
    }

    private ContractVO buildContractByVersion(List<ContractRecord> recordList,ContractTemplate template){
        ContractRecord contractRecord = recordList.stream().max(Comparator.comparingDouble(ContractRecord::getVersion)).get();
        if (template.getVersion()>contractRecord.getVersion()){
            ContractVO contractVO = buildContractByTemplate(template);
            return contractVO;
        }
        return null;
    }


    private List<ContractVO> buildContractByRecordList(List<ContractRecord> recordList){
        List<ContractVO> list = new ArrayList<>();
        Date date = new Date();
        if (CollUtil.isNotEmpty(recordList)){
            for (ContractRecord contractRecord : recordList) {
                ContractVO contractVO = new ContractVO();
                contractVO.setContractName(contractRecord.getContractName());
                contractVO.setContractState(AggreContractState.SIGNED.getType());
                if (contractRecord.getContractEndTime()!=null && contractRecord.getContractEndTime().getTime()<date.getTime()){
                    contractVO.setContractState(AggreContractState.EXPIRE.getType());
                }
                contractVO.setVersion("V"+contractRecord.getVersion());
                contractVO.setCustomerId(contractRecord.getCustomerId());
                contractVO.setContractStartTime(contractRecord.getContractStartTime());
                contractVO.setContractEndTime(contractRecord.getContractEndTime());
                contractVO.setContractUrl(contractRecord.getContractUrl());
                contractVO.setContractLink(contractRecord.getContractLink());
                contractVO.setCreateTime(contractRecord.getCreateTime());
                list.add(contractVO);
            }
        }

        return list;
    }



    /**
     * build一个未签署的合同
     * @return
     */
    private ContractVO buildContractByUnSign(Map<String, CommonContractVO> unSignMap,ContractTemplate template){
        CommonContractVO commonContractVO = unSignMap.get(template.getType());
        if (commonContractVO == null){
            return null;
        }
        ContractVO contractVO = buildContractByTemplate(template);
        contractVO.setContractState(AggreContractState.UN_SIGN.getType());
        contractVO.setContractStartTime(commonContractVO.getContractStartDate());
        contractVO.setContractEndTime(commonContractVO.getContractEndDate());
        contractVO.setContractUrl(commonContractVO.getContractUrl());
        contractVO.setContractLink(commonContractVO.getContractLink());
        contractVO.setCreateTime(commonContractVO.getCreateTime());
        return contractVO;
    }

    /**
     * 根据模版build合同
     * @return
     */
    private ContractVO buildContractByTemplate(ContractTemplate template){
        ContractVO contractVO = new ContractVO();
        contractVO.setContractName(template.getContractName());
        contractVO.setVersion("V"+template.getVersion());
        contractVO.setContractState(AggreContractState.REPLACED_SIGN.getType());
        contractVO.setCreateTime(new Date());
        contractVO.setType(template.getType());
        return contractVO;
    }
}
